#ifndef __ssh_hpp__
#define __ssh_hpp__

#include <croco/os/select.hpp>
#include <string>
#include <vector>

namespace croco
{

namespace ip
{
    class server_tcp;
}

namespace ssh
{

class integration
{
public:
    virtual ~integration() {}

    enum auth_methods
    {
        auth_no_auth = 1,
        auth_user_passd = 2,
        auth_public_key = 4,
        auth_host_based = 8
    };

    virtual int get_auth_methods() const = 0;

    virtual void unrestricted_auth() {}
    virtual bool verify_user_passwd(const std::string& user, const std::string& passwd);
    virtual bool verify_key(const std::string& publicKey);  // TODO a dedicated type for key is needed instead of std::string
    virtual bool verify_host(const std::string& hostName);

    enum PTY_SIZE_TYPE { PTY_WIDTH, PTY_HEIGHT, PTY_PXWIDTH, PTY_PXHEIGHT };
    template<PTY_SIZE_TYPE>
    struct int2type
    {
        explicit int2type(int v = -1) : value(v) {}
        int value;
    };
    typedef int2type<PTY_WIDTH> pty_width;
    typedef int2type<PTY_HEIGHT> pty_height;
    typedef int2type<PTY_PXWIDTH> pty_pxwidth;
    typedef int2type<PTY_PXHEIGHT> pty_pxheight;

    virtual void set_pty_name(const std::string& name) {}
    virtual void set_pty_size(const pty_width& w, const pty_height& h, const pty_pxwidth& pxw, const pty_pxheight& pxh) {}
    virtual void set_env_var(const std::string& name, const std::string& value) {}
};

class interface
{
public:
    interface(integration& intgr,
        const std::string& rsaKeyPath,
        const std::string& dsaKeyPath,
        const std::string& banner,
        os::select_timeout authTimeout,
        bool verbose = false);

    ~interface();
    void accept_connection(ip::server_tcp& socket);
    bool authenticate(const std::vector<int>& terms = std::vector<int>());
    int send(const char* buf, std::size_t size, const std::vector<int>& terms = std::vector<int>());
    int receive(char* buf, std::size_t size, const std::vector<int>& terms = std::vector<int>());
    int get_session_fd();
    bool is_eof() const;

private:
    // uncopyable
    interface(const interface&);
    interface& operator=(const interface&);

    void process_protocol_msgs();

    struct sshimpl; // forward declaration for the PIMPL idiom

    sshimpl* m_sshimpl;
    std::string m_rsaKeyPath;
    std::string m_dsaKeyPath;
    std::string m_banner;
    os::select_timeout m_authTimeout;
    int m_verbosity;
};

} // namespace ssh
} // namespace croco

#endif // __ssh_hpp__
